package core;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;

public class ByteBuf {
    private ByteBuffer buffer;
    private  int readerIndex=0;
    private int writerIndex=0;
    private int markIndex=-1;
    private int defaultSize;
    public ByteBuf(){
        defaultSize=1024;
        buffer=ByteBuffer.allocate(defaultSize);
    }

    public ByteBuf(int size){
        defaultSize=size;
        buffer=ByteBuffer.allocate(defaultSize);
    }

    public ByteBuffer getBuffer(){
        return buffer;
    }

    public ByteBuf put(byte[] src,int offset,int len){
        int needSize=len;
        int remainSize=this.buffer.capacity() - writerIndex;
        if( remainSize< needSize) {
            int toBeExtSize = needSize > 128 ? needSize : 128;
            ByteBuffer tmpBuffer = ByteBuffer.allocate(this.buffer.capacity() + toBeExtSize);
            // 保留0~readerIndex 读取过的空间以及readerIndex~writerIndex 有效空间
            tmpBuffer.put(this.buffer.array(),0,this.writerIndex);
            this.buffer = tmpBuffer;
            this.limit();
        }
        this.buffer.put(writerIndex,src,offset,len);
        this.writerIndex +=len;
        //buffer操作后要重置limit
        this.limit();

        return this;
    }

    public ByteBuf put(byte b){
        return put(new byte[]{b},0,1);
    }

    public ByteBuf put(byte[] bytes){
        return put(bytes,0,bytes.length);
    }

    public ByteBuf put(ByteBuffer buffer){
        buffer.flip();
        return put(buffer.array(),0,buffer.limit());
    }

    public byte[] get(int index,int len){
        //指定位置读，不改变读指针
        if (index<0) index=0;
        if (index+len>writerIndex) len=writerIndex -index;
        byte[] dst=new byte[len];
        buffer.get(index,dst);
        this.limit();
        return dst;
    }

    public byte[] get(int len){
        int canReadSize=writerIndex- readerIndex;
        int readSize=len>canReadSize?canReadSize:len;
        byte[] dst=new byte[readSize];
        buffer.get(readerIndex,dst);
        readerIndex+=readSize;
        //buffer操作后要重置limit
        this.limit();
        //buffer.position(readerIndex); //无需关心position
        return dst;
    }

    public byte[] get() {
        return get(getCanReadSize());
    }

    public ByteBuf clear()
    {
        readerIndex=0;
        writerIndex=0;

        return this;
    }

    public ByteBuf compress(){
        int remainSize=writerIndex -readerIndex;
        byte[] bytes=get(remainSize);
        int toMinSize = remainSize < defaultSize ? defaultSize : remainSize;
        ByteBuffer tmpBuffer = ByteBuffer.allocate(toMinSize);
        tmpBuffer.put(0,bytes);
        this.buffer = tmpBuffer;
        readerIndex=0;
        writerIndex=remainSize;
        //buffer操作后要重置limit
        this.limit();

        return this;
    }

    public ByteBuf compact(){
        if (readerIndex==0) return this;

        int remainSize=writerIndex -readerIndex;
        this.buffer.compact();//数据前移
        readerIndex=0;
        writerIndex=remainSize;
        //buffer操作后要重置limit
        this.limit();

        return this;
    }

    public int getCanReadSize() {
        return writerIndex -readerIndex;
    }

    public ByteBuf mark(){
        markIndex=readerIndex;
        return this;
    }

    public ByteBuf reset(){
        readerIndex=markIndex;
        return this;
    }

    public ByteBuf limit(){
        this.buffer.limit(this.buffer.capacity());
        return this;
    }

    public int capacity(){
        return this.buffer.capacity();
    }

    public boolean setReaderIndex(int index){
        if (index<0||index>this.writerIndex) return false;

        this.readerIndex=index;

        return true;
    }

    public boolean setWriterIndex(int index){
        if (index<0||index>this.buffer.capacity()) return false;

        this.writerIndex=index;

        return true;
    }

    public boolean moveReaderIndex(int index){
        return setReaderIndex(readerIndex+index);
    }

    public boolean moveWriterIndex(int index){
        return setReaderIndex(writerIndex+index);
    }

    //只输出，不改变读位置
    public byte[] toByteArray(){
        int readSize=writerIndex- readerIndex;
        byte[] dst=new byte[readSize];
        buffer.get(readerIndex,dst);
        return dst;
    }

    //只转String输出
    public String toString(Charset charset){
        return new String(toByteArray(),charset);
    }

}
